package com.apps.sworld.dao;

import com.apps.sexctption.DataException;
import com.apps.sexctption.DbException;
import com.apps.sexctption.NullException;
import com.apps.shelper.RedisCacheHelper;
import com.apps.sworld.enums.TimeUnit;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.apps.shelper.AnnotationHelper;
import com.apps.shelper.ClassHelper;
import com.apps.saspect.ValidMethod;
import com.apps.sannotation.constraints.NoNull;
import com.apps.sannotation.identity.GmtCreate;
import com.apps.sannotation.identity.GmtModify;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.toolkit.ExceptionUtils;
import com.baomidou.mybatisplus.core.toolkit.ReflectionKit;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.TableInfoHelper;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.Year;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * 管理员抽象接口基类,商城所有对象都是管理员的儿子,类比为神,万物皆被神管理
 */
public interface sGod<T> extends sDao<T> {

    /**
     * 获取对象的自增字段的名称
     * @return
     */
    default String getTableIdName()
    {
        return AnnotationHelper.getAnnotationFieldName(TableId.class,currentModelClass());
    }

    /**
     * 获取模型创建字段的名称
     * @return
     */
    default  String getGmtCreateName()
    {
        return AnnotationHelper.getAnnotationFieldName(GmtCreate.class,currentModelClass());
    }

    /**
     * 获取模型更新字段的名称
     * @return
     */
    default String getGmtModifyName()
    {
        return AnnotationHelper.getAnnotationFieldName(GmtModify.class,currentModelClass());
    }

    /**
     * 按条件查询结果是否为空?
     * @param wrapper 传null则校验整张表的数据是否为空
     * @return
     */
    default boolean isEmpty(QueryWrapper<T> wrapper)
    {
        if(null==wrapper)
            return count() <= 0 ? true : false;
        else
            return count(wrapper) <= 0 ? true : false;
    }

    /**
     * 按自增ID删除数据
     * @param id
     */
    @ValidMethod
    default void deleteById(@NoNull Integer id)
    {
        QueryWrapper<T> wrapper=new QueryWrapper<>();
        wrapper.eq(getTableIdName(),id);
        delete(wrapper);
    }

    /**
     * 保存或更新
     * @param entity
     * @return
     */
    @Transactional(rollbackFor = DbException.class)
    default T saveOrUpdate(T entity)
    {
        if (null != entity) {
            Class<?> cls = entity.getClass();
            TableInfo tableInfo = TableInfoHelper.getTableInfo(cls);
            if (null != tableInfo && StringUtils.isNotEmpty(tableInfo.getKeyProperty())) {
                Object idVal = ReflectionKit.getMethodValue(cls, entity, tableInfo.getKeyProperty());
                return StringUtils.checkValNull(idVal) || Objects.isNull(getOneById((Integer)idVal)) ? saveToDB(entity) : updateById(entity);
            } else {
                throw ExceptionUtils.mpe("Error:  Can not execute. Could not find @TableId.");
            }
        }
        return entity;
    }
    /**
     * 按某个字段名的值查询一条数据
     * @param filed
     * @param value
     * @return
     */
    @ValidMethod
    default T getOneByFieldValue(@NoNull String filed, @NoNull Object value)
    {
        T t= (T) RedisCacheHelper.getOne(getTableIdName(),value.toString(),this.getClass());
        if(null == t) {
            QueryWrapper<T> wrapper = new QueryWrapper<>();
            wrapper.eq(filed, value);
            t = getOne(wrapper);
        }
        return t;
    }

    /**
     * 按某个字段查询出所有相关记录
     * @param filed
     * @param value
     * @return
     */
    default List<T> queryByFieldValue(@NoNull String filed, @NoNull Object value)
    {
        List<T> result= (List<T>) RedisCacheHelper.query(filed,value.toString(),this.getClass());
        if(null == result)
        {
            QueryWrapper<T> wrapper = new QueryWrapper<>();
            wrapper.eq(filed, value);
            result = query(wrapper);
        }
        return result;
    }
    /**
     * 对某个字段进行like关键词查询
     * @param filed
     * @param value
     * @return
     */
    @ValidMethod
    default List<T> queryLikeFieldValue(@NoNull String filed, @NoNull Object value)
    {
        List<T> result=new ArrayList<>();
        QueryWrapper<T> wrapper=new QueryWrapper<>();
        wrapper.like(filed,value);
        return query(wrapper);
    }

    /**
     * 对某个字段进行like关键词查询,分页查询
     * @param filed
     * @param value
     * @param pageNo
     * @param pageSize
     * @return
     */
    @ValidMethod
    default IPage<T> pageQueryLikeFieldValue(@NoNull String filed, @NoNull Object value, int pageNo, int pageSize)
    {
        QueryWrapper<T> wrapper=new QueryWrapper<>();
        wrapper.like(filed,value);
        return pageQuery(wrapper,pageNo,pageSize);
    }

    /**
     * 按记录id更新某一条记录的某一个字段
     * @param id
     * @param fieldname
     * @param value
     */
    @ValidMethod
    default T updateOneFieldById(@NoNull Integer id,@NoNull String fieldname,@NoNull Object value)
    {
        T t=getOneById(id);
        if(null == t)
            throw new NullException("id为"+id+"的记录不存在");
        ClassHelper.setFiledValue(fieldname,t,value);
        return updateById(t);
    }

    /**
     * 取出fieldname=value的所有记录进行更新
     * @param t
     * @param wrapper
     * @param t  数据模型,里面不为空的字段会填充给待更新的记录
     * @return
     */
    @ValidMethod
    default List<T> updateToDB(@NoNull T t,@NoNull QueryWrapper<T> wrapper)
    {
        List<T> result=query(wrapper);
        if(null == result)
            result = new ArrayList<>();
        for(int i=0;i<result.size();i++)
        {
            ClassHelper.CopyNotNullFiled(result.get(i),t);
            updateById(result.get(i));
        }
       return result;
    }

    /**
     * 按ID获取一条数据
     * @param id
     * @return
     */
    @ValidMethod
    default T getOneById(@NoNull Integer id)
    {
        T t= (T) RedisCacheHelper.getOne(getTableIdName(),id.toString(),this.getClass());
        if(null == t) {
            QueryWrapper<T> wrapper = new QueryWrapper<>();
            wrapper.eq(getTableIdName(), id);
            t = getOne(wrapper);
        }
        return t;
    }

    /**
     * 如果获取不到就创建模型
     * @param id
     * @param t  待创建的模型
     * @return
     */
    @ValidMethod
    default T getOneById(@NoNull Integer id,@NoNull T t)
    {
        T result=getOneById(id);
        if(null == result)
        {
            String filedName=AnnotationHelper.getAnnotationFieldName(TableId.class,t.getClass());
            if(com.apps.sutils.StringUtils.isEmpty(filedName))
                throw new NullException("自增id不存在或没添加注解进行标识");
            Object filedValue=ClassHelper.getFiledValue(t,filedName);
            //为空则自动设置
            if(null== filedValue) {
                ClassHelper.setFiledValue(filedName, t, id);
                filedValue=id;
            }
            if(!filedValue.equals(id))
                throw new DataException("模型的自增id值必须等于传入的自增id");
            return saveToDB(t);
        }
        return result;
    }

    /**
     * 查出所有数据,无排序
     * @return
     */
    default List<T> query()
    {
        List<T> result= (List<T>) RedisCacheHelper.query(this.getClass());
        if(null==result)
          result= query(null);
        return result;
    }

    /**
     * 按创建时间区间查询所有数据
     * @param start
     * @param end
     * @return
     */
    @ValidMethod
    default List<T> queryTimeInterval(@NoNull LocalDateTime start, @NoNull LocalDateTime end)
    {
        List<T> result=new ArrayList<>();
        return queryTimeInterval(null,start,end);
    }


    /**
     * 按创建时间进行按年月日小时查询,传入的是字符串格式:2021090306 这样的格式
     * @param wrapper
     * @param date
     * @param timeUnit
     * @return
     */
    @ValidMethod
    default List<T> queryByGmtCreate(QueryWrapper<T> wrapper,@NoNull String date, @NoNull TimeUnit timeUnit)
    {
       if(null == wrapper)
           wrapper=new QueryWrapper<>();
        wrapper.eq("DATE_FORMAT("+getGmtCreateName()+", '"+timeUnit.getForMat()+"')",date.trim());
        return query(wrapper);
    }
    /**
     * 按创建时间进行按年月日小时分页查询,传入的是字符串格式:2021090306 这样的格式
     * @param wrapper
     * @param date
     * @param timeUnit
     * @return
     */
    @ValidMethod
    default IPage<T> pageQueryByGmtCreate(QueryWrapper<T> wrapper,@NoNull String date, @NoNull TimeUnit timeUnit,int pageNo, int pageSize)
    {
        if(null == wrapper)
            wrapper=new QueryWrapper<>();
        wrapper.eq("DATE_FORMAT("+getGmtCreateName()+", '"+timeUnit.getForMat()+"')",date.trim());
        return pageQuery(wrapper,pageNo,pageSize);
    }
    /**
     * 按创建时间区间查询所有数据,可添加条件,核心方法
     * @param wrapper
     * @param start
     * @param end
     * @return
     */
    @ValidMethod
    default List<T> queryTimeInterval(QueryWrapper<T> wrapper, @NoNull LocalDateTime start, @NoNull LocalDateTime end)
    {
        if(null == wrapper)
                wrapper=new QueryWrapper<>();
        String gmt_create_name=getGmtCreateName();
        wrapper.gt("unix_timestamp("+gmt_create_name+")",start.toEpochSecond(ZoneOffset.of("+8")));
        wrapper.lt("unix_timestamp("+gmt_create_name+")",end.toEpochSecond(ZoneOffset.of("+8")));

        return query(wrapper);
    }

    /**
     * 分页查询,无排序
     * @param pageNo
     * @param pageSize
     * @return
     */
    @ValidMethod
    default IPage<T> pageQuery(int pageNo, int pageSize)
    {
        return pageQuery(null,pageNo,pageSize);
    }

    /**
     * 按某个字段的值分页查询
     * @param filed
     * @param value
     * @param pageNo
     * @param pageSize
     * @return
     */
    @ValidMethod
    default IPage<T> pageQueryByFieldValue(@NoNull String filed, @NoNull Object value, int pageNo, int pageSize)
    {
        QueryWrapper<T> wrapper=new QueryWrapper<>();
        wrapper.eq(filed,value);
        return pageQuery(wrapper,pageNo,pageSize);
    }


    /**
     * 按创建时间区间分页查询
     * @param start 开始时间
     * @param end 结束时间
     * @return
     */
    @ValidMethod
    default IPage<T> pageQueryTimeInterval(@NoNull LocalDateTime start, @NoNull LocalDateTime end, int pageNo, int pageSize)
    {
        return pageQueryTimeInterval(null,start,end,pageNo,pageSize);
    }


    /**
     * 按创建时间区间分页查询,可添加条件,核心方法
     * @param wrapper
     * @param start
     * @param end
     * @param pageNo
     * @param pageSize
     * @return
     */
    @ValidMethod
    default IPage<T> pageQueryTimeInterval(QueryWrapper<T> wrapper, @NoNull LocalDateTime start, @NoNull LocalDateTime end, int pageNo, int pageSize)
    {
        if(null == wrapper)
            wrapper=new QueryWrapper<>();
        String gmt_create_name=getGmtCreateName();
        wrapper.gt("unix_timestamp("+gmt_create_name+")",start.toEpochSecond(ZoneOffset.of("+8")));
        wrapper.lt("unix_timestamp("+gmt_create_name+")",end.toEpochSecond(ZoneOffset.of("+8")));

        return pageQuery(wrapper,pageNo,pageSize);
    }


}
